package cn.gddevon.beans.factory.xml;

import cn.gddevon.beans.BeanDefinition;
import cn.gddevon.beans.MutablePropertyValues;
import cn.gddevon.beans.PropertyValue;
import cn.gddevon.beans.anno.OnAnnotation;
import cn.gddevon.beans.aop.OnAspect;
import cn.gddevon.beans.factory.support.BeanDefinitionReader;
import cn.gddevon.beans.factory.support.BeanDefinitionRegistry;
import cn.gddevon.beans.factory.support.SimpleBeanDefinitionRegistry;
import cn.gddevon.exception.Xml2DefinitionException;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;

/**
 * 用于读取xml文件中的bean并且放入到registry中
 */
public class XmlBeanDefinitionReader implements BeanDefinitionReader {

    // 声明注册表对象
    private BeanDefinitionRegistry registry;
    // 注解实例化帮助类
    private OnAnnotation onAnnotation;
    // 开启aop增强类
    private OnAspect onAspect;

    public XmlBeanDefinitionReader(){
        this.registry = new SimpleBeanDefinitionRegistry();
    }

    @Override
    public BeanDefinitionRegistry getRegistry() {
        return registry;
    }

    public OnAnnotation getOnAnnotation() {
        return onAnnotation;
    }

    public OnAspect getOnAspect() {
        return onAspect;
    }

    // 加载xml配置文件并且将Definition放入到registry中
    @Override
    public void loadBeanDefinitions(String configLocation) {
        try {
            // 使用dom4j进行xml配置文件解析
            SAXReader reader = new SAXReader();
            // 获取类路径下的配置文件
            InputStream is = XmlBeanDefinitionReader.class.getClassLoader().getResourceAsStream(configLocation);
            Document doc = null;

            doc = reader.read(is);

            // 根据document对象获取根标签对象（beans）
            Element rootElement = doc.getRootElement();
            // 获取根标签下所有的bean标签对象
            List<Element> beanElements = rootElement.elements("bean");
            for (Element beanElement : beanElements) {
                // 获取id属性
                String id = beanElement.attributeValue("id");
                // 获取class属性
                String className = beanElement.attributeValue("class");
                String scope = beanElement.attributeValue("scope");
                // 封装数据到BeanDefinition对象
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setId(id);
                beanDefinition.setClassName(className);
                if(scope == null || "singleton".equals(scope)){
                    beanDefinition.setScope("singleton");
                } else if("prototype".equals(scope)){
                    beanDefinition.setScope("prototype");
                    // 当scope错误时
                } else {
                    throw new Xml2DefinitionException("bean scope is error");
                }

                // 创建
                MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();

                // 获取bean标签下所有的Property标签对象
                List<Element> propertyElements = beanElement.elements("property");
                for (Element propertyElement : propertyElements) {
                    PropertyValue propertyValue = new PropertyValue(
                            propertyElement.attributeValue("name"),
                            propertyElement.attributeValue("ref"),
                            propertyElement.attributeValue("value")
                    );
                    mutablePropertyValues.addPropertyValue(propertyValue);
                }

                // 封装property到definition中
                beanDefinition.setMutablePropertyValues(mutablePropertyValues);
                registry.registerBeanDefinition(id, beanDefinition);
        }

            // 是否需要开启注解扫描功能
            List<Element> onAnnos = rootElement.elements("on-anno");
            if(onAnnos.size() > 0){
                Element onAnno = onAnnos.get(0);
                String classes = onAnno.attributeValue("classes");
                OnAnnotation onAnnotation = OnAnnotation.getInstance(classes);
                this.onAnnotation = onAnnotation;
            }

            // 检测是否开启aop切面功能
            List<Element> onAspects = rootElement.elements("on-aspect");
            if(onAspects.size() > 0){
                Element onAspect = onAspects.get(0);
                String classes = onAspect.attributeValue("classes");
                OnAspect onAspectObj = OnAspect.getInstance(classes);
                this.onAspect = onAspectObj;
            }

        } catch (DocumentException | Xml2DefinitionException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
